﻿namespace NumericalData.SolvationMethods.Async
open System
open NumericalData
open System.Diagnostics
open System.Threading
open NumericalData.Systems
open NumericalData.SolvationMethods
open NumericalData.Exceptions

type AsyncSolveFactory = 
    class
    static member internal Generate<'input,'output when 'output :> Answer > (solvMethod:'input -> 'output) 
        (inputData:'input) (asyncSuccess:Action<'output>) (asyncFail:Action<exn>) (asyncCancel:Action<OperationCanceledException>) = 
                let successClearFunc    = fun (ans:'output) ->
                                                asyncSuccess.Invoke(ans)
                let failClearFunc       = fun (exc:exn) ->
                                                asyncFail.Invoke(exc)
                let cancelClearFunc     = fun (exc:OperationCanceledException) ->
                                                asyncCancel.Invoke(exc)    

                let asyncSolve (inputData:'input) = 
                    let solve = new Func<'input,'output>(solvMethod)
                    Async.FromBeginEnd(
                        (inputData),
                        solve.BeginInvoke,
                        solve.EndInvoke)                
                let asyncOp = 
                    Async.TryCancelled(
                        (async{
                            return! asyncSolve inputData
                        }),
                        cancelClearFunc)
                let cancellationSource = new CancellationTokenSource()                                                                
                Async.StartWithContinuations(   asyncOp,
                                                successClearFunc,
                                                failClearFunc,
                                                cancelClearFunc,
                                                cancellationSource.Token
                                            )
                cancellationSource
    end

type IAsyncSolvable<'output when 'output :> BaseAnswer> = 
    interface
        abstract AsyncSolve: SLAE -> double -> bool -> int -> 
            Action<'output> -> Action<Exception> -> Action<OperationCanceledException> -> 
            CancellationTokenSource
    end